﻿using System;
using System.IO;
using Softec.AprSharp;
using Softec.SubversionSharp;
using System.Runtime.InteropServices;
using USU.MetricsMonitor.Common;

namespace USU.MetricsMonitor.DiffProvider
{
    /// <summary>
    /// Используется сторонняя библиотека Softec
    /// </summary>
    public class SoftecDiffProvider : BaseDiffProvider
    {
        static SoftecDiffProvider()
        {
            string LibPath = Directory.GetCurrentDirectory() + @"\Lib\";
            LoadLibraries(LibPath);
        }

        public SoftecDiffProvider(string repositaryPath, string diffLocalDirectory)
            : base(repositaryPath, diffLocalDirectory) { }

        [DllImport("kernel32.dll")]
        private static extern IntPtr LoadLibrary(string libFileName);

        private static void LoadLibraries(string libPath)
        {
            LoadLibrary(libPath + "libapr.dll");
            LoadLibrary(libPath + "intl3_svn.dll");
            LoadLibrary(libPath + "libapriconv.dll");
            LoadLibrary(libPath + "libaprutil.dll");
            LoadLibrary(libPath + "libdb44d.dll");
            LoadLibrary(libPath + "libeay32.dll");
            LoadLibrary(libPath + "Mono.GetOptions.dll");
            LoadLibrary(libPath + "ssleay32.dll");
            LoadLibrary(libPath + "svn_client-1.dll");
        }

        public override Stream GetStream(Revision rev)
        {
            string fileDiffPath = Path.Combine(DiffLocalDirectory, String.Format("{0}.diff", rev));

            if (!File.Exists(fileDiffPath))
            {
                GetNetDiff(fileDiffPath, rev);
            }

            FileStream file = File.Open(fileDiffPath, FileMode.Open, FileAccess.Read);
            return file;
        }

        private static AprFile GetTempAprFile(AprPool pool, string path)
        {
            AprFile aprFile = AprFile.Open(path,
                AprFile.Flags.Create | AprFile.Flags.Write,
                AprFile.Perms.OSDefault, pool);

            return aprFile;
        }

        private void SubGetNetDiff(string fileDiffPath, string repositDiffPath, Revision rev)
        {
            string fileErrorDiffPath = String.Format(@"{0}ErrorDiff.diff", repositDiffPath);

            try
            {
                SvnClient client = new SvnClient();

                int revision = (int)rev.Long();
                SvnRevision reva = new SvnRevision(revision - 1);
                SvnRevision revb = new SvnRevision(revision);

                AprFile FileOut = GetTempAprFile(client.Pool, fileDiffPath);
                AprFile FileErr = GetTempAprFile(client.Pool, fileErrorDiffPath);

                client.AddSimpleProvider();
                client.AddUsernameProvider();
                client.OpenAuth();

                client.Diff(new string[] { },
                    RepositaryPath,
                    reva,
                    RepositaryPath,
                    revb,
                    true,
                    true,
                    true,
                    true,
                    FileOut,
                    FileErr);

                FileOut.Close();
                FileErr.Close();

                client.Pool.Destroy();
            }
            catch (Exception ex)
            {
                throw new DiffProviderException("Error reception diff from Internet", ex);
            }
            finally
            {
                if (File.Exists(fileErrorDiffPath))
                    File.Delete(fileErrorDiffPath);
            }
        }

        /// <summary>
        /// Библиотека Softec не умеет работать с "неанглийскими" путями.
        /// Поэтому, если путь к кэшу диффов "неанглийский", то с начала считываем диффы папку 
        /// с "английским" путём, а затем переносим в папку с нашим "неанглийским" путём
        /// </summary>
        /// <param name="fileDiffPath"></param>
        /// <param name="rev"></param>
        private void GetNetDiff(string fileDiffPath, Revision rev)
        {
            if (!DiffLocalDirectory.IsEnglishPath())
            {
                string root = Directory.GetDirectoryRoot(DiffLocalDirectory);
                string tempFileDiffPath = String.Format(@"{0}{1}.diff", root, rev);

                try
                {
                    SubGetNetDiff(tempFileDiffPath, root, rev);
                    File.Move(tempFileDiffPath, fileDiffPath);
                }
                finally
                {
                    if (File.Exists(tempFileDiffPath))
                        File.Delete(tempFileDiffPath);
                }
            }
            else
            {
                SubGetNetDiff(fileDiffPath, DiffLocalDirectory, rev);
            }
        }
    }
}
